﻿const __0x1B1303324F0__net = require('net');
const __0x1B130332570__fs = require('fs');

const __0x1B130332530__CMD_ID = {
    CMD_SendTlv        : 0x1,
    CMD_SendIIC        : 0x2,
    CMD_ShowMsg        : 0x3,
    CMD_ToastInfo      : 0x4,
    CMD_ToastWarning   : 0x5,
    CMD_ToastError     : 0x6,
    CMD_ToastSuccess   : 0x7,
    CMD_SelectFile     : 0x8,
};

const IIC_STATUS = {
    NULL               : 0x0,
    BUSY               : 0x1,
    END_RECEIVE        : 0x3,
    END_SEND           : 0x4,
    ERR_MASTER_NCK     : 0x6,
};

const TlvTag = {
    Tlv_seq_id                     : 0,       // 通讯ID
    Tlv_status                     : 1,       // 通讯状态
    Tlv_reserve                    : 2,       // 通讯预留
    Tlv_IIC_feedback               : 3,       // IICA0反馈
    Tlv_IIC_IIC_CALL               : 4,       // IICA0调用
    Tlv_Interrupt_resp             : 5,       // 中断响应
    Tlv_MCU_RESET                  : 8,       // MCU复位
    Tlv_TOUCH_EVENT                : 9,       // 标准触摸报点
    Tlv_MCU_Product_STATUS         : 10,      // mcu产品(项目)状态，例如adc、ntc、背光fault等
    Tlv_MCU_Release_TimeStamp      : 11,      // 软件释放时间戳
    Tlv_MCU_RAM_Data               : 12,      // mcu指定RAM的值
    Tlv_MCU_Product_STD_Frame      : 13,      // 产品通讯_标准帧
    Tlv_MCU_Product_EXT_Frame      : 14,      // 产品通讯_扩展帧
    Tlv_MCU_Product_REC_Frame      : 15,      // 产品通讯_接收帧
    Tlv_MCU_Warning                : 16,      // mcu发出的警告消息（具体场景自定义）
    Tlv_MCU_String                 : 17,      // mcu发出的字符串信息（具体场景自定义）
    Tlv_MCU_Dump                   : 18,      // 前4字节为地址，mcu将自身内存传出，需先发tag19
    Tlv_MCU_DumpControl            : 19,      // dump控制信息（开始结束、起始地址等）
    Tlv_MCU_ROM_Data               : 20,      // mcu指定ROM的值
    Tlv_MCU_BOOT_APP_REQ           : 21,      // 请求boot还是APP
    Tlv_MCU_BOOT_APP_RSP           : 22,      // [1=boot, 2=APP] + N字节版本信息
    Tlv_MCU_Program_REQ            : 23,      // 4字节地址(大端) + N字节数据
    Tlv_MCU_Program_RSP            : 24,      // 4字节地址(大端) + 1字节结果(0成功，其它失败原因)
    Tlv_MCU_Enter_BOOT             : 25,      // 请求进入boot
    Tlv_MCU_CAN_TX_REQ             : 26,      // 15765消息
    Tlv_MCU_CAN_TX_RSP             : 27,      // TBD
    Tlv_MCU_CAN_RX                 : 28,      // 15765消息
    Tlv_MCU_SET_IO                 : 29,      // 2字节编号 + 1字节类型(1高低电平,2PWM) + 2字节值(65535=PWM100%)
    Tlv_MCU_ADC_REQ                : 30,      // 2字节编号
    Tlv_MCU_ADC_RSP                : 31,      // 2字节编号 + 2字节ADC值
    Tlv_MCU_REQ_RSP                : 32,      // 通用响应: 2字节cmdid + 1字节状态; 状态: 1未定义; 2未实现; 3非自身功能
    Tlv_PL_IIC_RSP                 : 33,      // 产线IIC响应，60805(ED85)响应
    Tlv_IntnCall_RSP               : 34,      // 内置函数请求响应，60806(ED86)响应
    Tlv_PL_IIC_REQ                 : 0xED85,  // 产线IIC请求
    Tlv_IntnCall                   : 0xED86   // 内置函数请求
};

const __0x1B1303324F0__ToolFunc = {
    isHexString(str) {
        str = str.replace(/\s/g, '');
        return !(/[^0-9A-Fa-f]/.test(str));
    },
    isDecString(str) {
        str = str.replace(/\s/g, '');
        return !(/[^0-9]/.test(str));
    },
    hexStr2Arr(hexStr) {
        hexStr = hexStr.replace(/\s/g, '');
        // 检查是否包含非十六进制字符
        if (!this.isHexString(hexStr)) {
            throw new Error('Invalid character in hex string.');
        }
        // 检查长度是否为偶数
        if (hexStr.length % 2 !== 0) {
            throw new Error('The length of hex string is not even.');
        }
        const byteArray = [];
    
        // 每两个字符解析为一个字节
        for (let i = 0; i < hexStr.length; i += 2) {
            const byteStr = hexStr.substr(i, 2);
            const byteValue = parseInt(byteStr, 16);
            byteArray.push(byteValue);
        }
        
        return byteArray;
    },
    checkTlvTag(tag) {
        if (typeof tag === 'string') {
            if (!this.isHexString(tag)) 
                throw new Error('tlv tag format is wrong.');
            tag = parseInt(tag, 16);
        }
        return tag.toString(16);
    },
    checkTlvValue(value) {
        if (typeof value === 'string') {
            value = this.hexStr2Arr(value);
        }
        let hexStr = '';
        for (let i = 0; i < value.length; i++) {
            if (value[i] > 0xFF || value < 0x00) {
                throw new Error('A hex number must in 0x00~0xFF');
            }
            hexStr += value[i].toString(16).padStart(2, '0');
        }
        return hexStr;
    },
    checkIICAddr(addr) {
        if (typeof addr === 'string') {
            if (!this.isHexString(addr)) 
                throw new Error('iic addr format is wrong.');
            addr = parseInt(addr, 16);
        }
        if (addr > 0x7F) {
            throw new Error('7bit iic addr is 0x7F at most!');
        }
        return addr.toString(16);
    },
    checkIICData(data) {
        return this.checkTlvValue(data);
    },
    checkIICReadlen(readlen) {
        if (typeof readlen === 'string') {
            readlen = readlen.replace(/\s/g, '');
            if (readlen == '') {
                readlen = 0;
            } else {
                if (!this.isDecString(readlen)) 
                    throw new Error('iic readlen format is wrong.');
                readlen = parseInt(readlen);
            }
        }
        if (readlen > 255 || readlen < 0) {
            throw new Error('iic readlen is in 0~255');
        }
        return readlen.toString();
    },
    checkMsg(msg) {
        if (typeof msg !== 'string') {
            throw new Error('showmsg msg format is wrong.');
        }
        return msg;
    },
    checkMsgFontsize (fontsize) {
        if (isNaN(fontsize) || typeof fontsize !== 'number') {
            throw new Error('showmsg fontsize format is wrong.');
        }
        return fontsize;
    }
};


function __0x1B130332570__QtBridge() {
    const RUNNER_NAME = "TlvTool_APIBridgeCom";
    const socketName = process.platform === 'win32'
        ? `\\\\.\\pipe\\${RUNNER_NAME}`   // Windows 命名管道路径
        : `/tmp/${RUNNER_NAME}`;           // Unix Domain Socket 路径

    const client = __0x1B1303324F0__net.createConnection(socketName, () => {
        // console.log('Connected to Qt application');
    });

    let buffer = '';
    let retryCnt = 3;
    let retryTimeout = 2000;

    this.available = () => {
        return !!(client && client.writable);
    }

    this.close = () => {
        if (client) {
            client.end();
            client.destroy();
        }
    }

    this.setRetryCnt = (cnt) => {
        retryCnt = cnt;
    }

    this.setRetryTimeout = (timeout) => {
        retryTimeout = timeout;
    }

    this.write = (data) => {
        if (this.available()) {
            let msg = "";

            if (typeof data === 'object') {
                msg = JSON.stringify(data);
            } else if (typeof data === 'string') {
                msg = data;
            }

            if (!msg.endsWith('\n')) {
                msg += '\n';
            }
            client.write(msg);
        } else {
            console.error('Socket is not writable');
        }
    }

    /**
     * 封装：单次发送+等待结果（内部使用）
     */
    const tryOnce = (data, timeoutMs) => {
        return new Promise((resolve, reject) => {
            let buffer = '';
            let timeoutId = null;

            const onData = (recvData) => {
                buffer += recvData.toString();
                if (buffer.includes('\n')) {
                    clearTimeout(timeoutId);
                    // 取到第一条完整消息
                    const [msg] = buffer.split('\n');
                    buffer = '';
                    try {
                        const json = JSON.parse(msg);
                        client.removeListener('data', onData);
                        resolve(json);
                    } catch (e) {
                        // 可能是心跳包，继续等待
                        buffer = '';
                    }
                }
            };

            client.on('data', onData);

            // 写入数据
            this.write(data);

            // 超时控制
            timeoutId = setTimeout(() => {
                client.removeListener('data', onData);
                reject(new Error('Timeout waiting for response!!!'));
            }, timeoutMs);
        });
    };

    /**
     * 带超时重试的同步写
     */
    this.syncWrite = async (data) => {
        let attempt = 0;
        let lastError = null;

        while (attempt <= retryCnt) {
            try {
                return await tryOnce(data, retryTimeout);  // 成功返回
            } catch (err) {
                lastError = err;
                attempt++;
                if (attempt > retryCnt) break;  // 超过重试次数
                console.warn(`syncWrite timeout, retrying ${attempt}/${retryCnt}...`);
            }
        }

        // 所有重试都失败
        throw lastError || new Error('Unknown error in syncWrite');
    }
}

const __0x1B130332530__ipc = new __0x1B130332570__QtBridge();

const Toast = new (function() {
    const toast = async (cmdid, msg, duration) => {
        const json = {
            "cmd": cmdid,
            "msg": msg,
            "duration": duration
        };
        return await __0x1B130332530__ipc.syncWrite(json);
    }

    this.info     = (msg, duration=2000) => toast(__0x1B130332530__CMD_ID.CMD_ToastInfo,    msg, duration);
    this.warning  = (msg, duration=2000) => toast(__0x1B130332530__CMD_ID.CMD_ToastWarning, msg, duration);
    this.error    = (msg, duration=2000) => toast(__0x1B130332530__CMD_ID.CMD_ToastError,   msg, duration);
    this.success  = (msg, duration=2000) => toast(__0x1B130332530__CMD_ID.CMD_ToastSuccess, msg, duration);
})();


function Exit(code=0) {
    __0x1B130332530__ipc.close();
    process.exit(code);
}

function SetRetryCnt(cnt) {
    __0x1B130332530__ipc.setRetryCnt(cnt);
}

function SetRetryTimeout(timeout) {
    __0x1B130332530__ipc.setRetryTimeout(timeout);
}

function ReadFile(filepath) {
    return __0x1B130332570__fs.readFileSync(filepath);
}

async function Sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

function Available() {
    return __0x1B130332530__ipc.available();
}

async function SendTlv(tag, value) {
    const json = {
        "cmd": __0x1B130332530__CMD_ID.CMD_SendTlv,
        "tag": __0x1B1303324F0__ToolFunc.checkTlvTag(tag),
        "value": __0x1B1303324F0__ToolFunc.checkTlvValue(value)
    };
    const res = await __0x1B130332530__ipc.syncWrite(json);
    return {
        "tag": res.tag,
        "value": Buffer.from(res.value, 'base64')
    };
}

async function SendIIC(addr, data, readlen=0) {
    const json = {
        "cmd": __0x1B130332530__CMD_ID.CMD_SendIIC,
        "addr": __0x1B1303324F0__ToolFunc.checkIICAddr(addr),
        "data": __0x1B1303324F0__ToolFunc.checkIICData(data),
        "readlen": __0x1B1303324F0__ToolFunc.checkIICReadlen(readlen)
    };
    const res = await __0x1B130332530__ipc.syncWrite(json);
    return {
        "status": res.status,
        "data": Buffer.from(res.data, 'base64')
    };
}

async function ShowMsg(msg, fontSize=100) {
    const json = {
        "cmd": __0x1B130332530__CMD_ID.CMD_ShowMsg,
        "msg": __0x1B1303324F0__ToolFunc.checkMsg(msg),
        "fontsize": __0x1B1303324F0__ToolFunc.checkMsgFontsize(fontSize)
    };
    return await __0x1B130332530__ipc.syncWrite(json);
}

async function SelectFile(title="Select File") {
    const json = {
        "cmd": __0x1B130332530__CMD_ID.CMD_SelectFile,
        "title": title
    };
    const res = await __0x1B130332530__ipc.syncWrite(json);
    return res.filepath;
}

async function __0x1B1303324F0__main() {
    await Sleep(100);  // 等待100ms，确保 IPC 连接建立
    SetRetryTimeout(100);
    SetRetryCnt(100);
    
    /*USERDEF_SCRIPTS_INPUT*/

}

__0x1B1303324F0__main();
